/**
 *	6.如你所知，C编译器为数组分配下标时总是从0开始，而且当程序使用下标访问数组元素时，它并不检查下标的有效性，
 *	在这个项目中，你将要编写一个函数，允许用户访问“伪数组”，它的下标范围可以任意指定，并伴以完整的错误检查。
 *	下面是你将要编写的这个函数的原型：
 *	int array_offset(int arrayinfo[],...);
 *	这个函数接受一些用于描述伪数组的维数信息以及一组下标值，使用这个函数，用户既可以以向量的形式分配内存空间，
 *	也可以使用mallco分配空间，但按照多维数组的形式访问这些空间，这个数组之所以被称为“伪数组”是因为编译器以为它是个向量，
 *	尽管这个函数允许它按照多维数组的形式进行访问。
 *	这个函数的参数如下：
 *	参数                                      含义
 *	arrayinfo                        一个可变长度的整型数组，包含一些关于伪数组的信息。arrayinfo[0]指定伪数组具有的
 *									维数，它的值必须在1和10之间。arrayinfo[1]和arrayinfo[2]给出第一维的下限和上限。
 *									arrayinfo[3]和arrayinfo[4]给出第2维的下限和上限，依次类推。
 *
 *	...                              参数列表的可变部分可能包含多达10个的整数，用于标识伪数组中某个特定位置的下标
 *									 值。你必须使用va_参数访问它们，当函数被调用时，arrayinfo[0]参数将会被传递。
 *
 *	公式根据下面给出的下标值计算一个数组的位置。变量s1,s2等代表下标参数s1,s2等。变量lo1和hi1代表下标s1的下限和上限，
 *	它们来源于arrayinfo参数，其余各维以此类推。变量loc表示伪数组的目标位置，它用一个距离伪数组起始位置的整型偏移量表示。
 *	对于一维数组：
 *		loc = s1 - lo1
 *	对于二维伪数组：
 *		loc = (s1 - lo1) × (hi2 - lo2 + 1) + s2 - lo2
 *	对于三维伪数组：
 *		loc = [(s1 - lo1) × (hi2 - lo2 + 1) + s2 - lo2] × (hi3 - lo3 + 1) + s3 - lo3
 *	对于四维伪数组：
 *		loc = [[(s1 - lo1) × (hi2 - lo2 + 1) + s2 - lo2] × (hi3 - lo3 + 1) + s3 - lo3] × (hi4 - lo4 + 1) + s4 - lo4
 *	
 *	一直到第十维为止，都可以类似的使用这种方法推导出loc的值。你可以假定arrayinfo是个有效的指针，
 *	传递给array_offset的下标参数也是正确的。对于其他情况你必须进行错误检查，可能出现的一些错误有：
 *	维的数目不处于1到10之间，下标小于low值，low值大于其对应的high值等，如果检测到这些或者其他错误，函数应该返回-1.
 *
 *	提示：把下标参数都复制到一个局部数组中，你接着便可以把计算过程以循环的形式编码，对每一维都使用一次循环。
 *
 *	举例：假定arrayinfo包含值2,4,6,1,5,-3,3.这些值提示我们所处理的是三维伪数组，第一个下标范围从4到6,
 *	第二个下标范围从1到5,第三个下标范围从-3到3,在这个例子中，array_offset被调用时将有三个下标参数传递给它，
 *	下面显示了几组下标值以及它们所代表的偏移量：
 *	subscripts		offset		subscripts		offset		subscripts		offset
 *	4,1,-3			0			4,1,3			6			5,1,-3			35
 *	4,1,-2			1			4,2,-3			7			6,3,1			88
**/

#include <stdio.h>
#include <stdarg.h>

int array_offsetp(int arrayinfo[], ...);

int main()
{
	int arr[] = {2,4,6,1,5,-3,3};

	printf("offset = %d\n", array_offsetp(arr, 4, 2, -3));
	
	return 0;
}

// 使用下标
int array_offset(int arrayinfo[], ...)
{
	int temp[10];
	int offset = 0;
	va_list var_list;
	int i;

	if(arrayinfo[0] <= 1 || arrayinfo[0] > 10)
		return -1;

	va_start(var_list, arrayinfo);
	for(i = 0; i < arrayinfo[0]; i++)
		temp[i] = va_arg(var_list, int);
	va_end(var_list);

	for(i = 0; i < arrayinfo[0]; i++)
	{
		if(i % 2 == 0 && arrayinfo[2 * i] >= temp[i] && arrayinfo[2 * i + 1] <= temp[i])
			return -1;
		offset *= (arrayinfo[2 * i] - arrayinfo[2 * i - 1] + 1);
		offset += temp[i] - arrayinfo[2 * i - 1];
	}
	return offset;
}

//使用指针
int array_offsetp(int arrayinfo[],...)
{
    int ndim;
    int offset;
    int hi,lo;
    int i;
    int s[10];
    va_list subscripts;
    va_start(subscripts,arrayinfo);
    ndim = *arrayinfo++;
    if(ndim >= 1 && ndim <= 10){
        for(i = 0; i < ndim; i += 1)
            s[i] = va_arg(subscripts,int);
        va_end(subscripts);

        offset = 0;
        for(i = 0; ndim;ndim--,i++){
            lo = *arrayinfo++;
            hi = *arrayinfo++;
            if(s[i] < lo || s[i] > hi)
                return -1;
            offset *= hi - lo + 1;
            offset += s[i] - lo;
        }
        return offset;
    }
    return -1;
}
